package com.ueboot.weishop.api.mq.receiver;

import com.alibaba.fastjson.JSON;
import com.rabbitmq.client.Channel;
import com.ueboot.weishop.api.component.OrderProcesser;
import com.ueboot.weishop.api.controller.order.vo.OrderReq;
import com.ueboot.weishop.api.mq.config.QueuesType;
import com.ueboot.weishop.entity.activity.ActivityEntity;
import com.ueboot.weishop.entity.goods.GoodsInfoEntity;
import com.ueboot.weishop.entity.order.OrderEntity;
import com.ueboot.weishop.service.activity.ActivityService;
import com.ueboot.weishop.service.cache.CacheService;
import com.ueboot.weishop.service.goods.GoodsInfoService;
import com.ueboot.weishop.service.order.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.util.Assert;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * MQ消费-订单处理
 *
 * @author yangkui
 */
@Component
@Slf4j
public class OrderMessageReceiver {
    @Autowired
    private OrderService orderService;

    @Autowired
    private ActivityService activityService;

    @Autowired
    private GoodsInfoService goodsInfoService;

    @Autowired
    private CacheService cacheService;

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Autowired
    private OrderProcesser orderProcesser;


    /***
     * 订单处理，设置的排他性策略，多个应用启动时，同时只有一个应用会接收到消息，如果应用停止后，会由其他应用自动接管
     * 设置了确认模式，只有消费成功，消息才会被从MQ中删除
     * 设置了同时只有一个消费端，每次只获取一条消息
     * @param object
     */
    @RabbitHandler
    @RabbitListener(queues = QueuesType.ORDER_SUBMIT_SYNC, containerFactory = "submitOrderTaskContainerFactory", exclusive = true)
    public void orderSubmit(Object object, Channel channel) {
        OrderReq req = null;
        Message m = (Message) object;
        try {
            String message = new String(m.getBody(), "UTF-8");
            if (StringUtils.isEmpty(message)) {
                log.info("消息内容为空，不处理！");
                return;
            }
            log.info("订单处理器接收到消息:{}", message);
            req = JSON.parseObject(message, OrderReq.class);

            ActivityEntity act = null;
            if (req.getActId() != null) {
                act = activityService.findById(req.getActId());
            } else {
                act = activityService.findBySn(req.getSn());
            }
            //活动统计缓存key值
            String actCountCacheKey = act.getSn() + ":" + act.getId();

            //是否允许购买
            boolean allowBuy = false;
            String json = goodsInfoService.findById(req.getGoodsInfoId());
            if (json == null) {
                cacheService.incrActOrderError(actCountCacheKey);
                cacheService.setRequestIdStatus(req.getRequestId(), "ERROR:商品信息不存在!");
                return;
            }
            GoodsInfoEntity goods = JSON.parseObject(json, GoodsInfoEntity.class);
            orderProcesser.getPayAmountAndLimitCount(actCountCacheKey, act, goods, req);
            //限购的库存数
            Integer limitCount = req.getLimitCount();
            //支付金额
            Integer payAmount = req.getPayAmount();

            Assert.notNull(payAmount);
            payAmount = req.getGoodsInfoCount() * payAmount;
            //已经购买的数量
            Integer alreadyBuyCount = cacheService.getAlreadyBuyCount(actCountCacheKey, req.getCountKey());
            log.info("当前活动:{}已经购买的数量:{}", act.getName(), alreadyBuyCount);
            //4.检查现在已经购买的数量和商品可购买数量是否允许购买
            if (limitCount != null && alreadyBuyCount != null && alreadyBuyCount >= limitCount) {
                // 从回滚的库存队列当中获取回滚数量，如果回滚的库存数量也不足时，提示无法购买
                Long rollbackOrder = cacheService.countRollbackOrder(actCountCacheKey+":"+req.getCountKey());
                log.info("回滚库存可以购买数量:{},key:{}",rollbackOrder,actCountCacheKey+":"+req.getCountKey());
                if (rollbackOrder < req.getGoodsInfoCount()) {
                    cacheService.incrActOrderFail(actCountCacheKey);
                    cacheService.setRequestIdStatus(req.getRequestId(), "ERROR:当前需要购买的商品库存不足!");
                    return;
                } else {
                    allowBuy = true;
                    for(int i=0;i<req.getGoodsInfoCount();i++){
                        //减少回滚库存数量，防止超卖
                        cacheService.popRollbackOrder(actCountCacheKey+":"+req.getCountKey());
                    }
                }
            }
            //校验是否已经大于库存数
            if (!allowBuy) {
                //5.分配库存序号
                Long orderIndex = cacheService.incrAlreadyBuyCount(actCountCacheKey, req.getCountKey(), Long.valueOf(req.getGoodsInfoCount()));
                if (limitCount != null && orderIndex > limitCount) {
                    cacheService.incrAlreadyBuyCount(actCountCacheKey, req.getCountKey(), -Long.valueOf(req.getGoodsInfoCount()));
                    cacheService.incrActOrderFail(actCountCacheKey);
                    cacheService.setRequestIdStatus(req.getRequestId(), "ERROR:当前选择的商品库存不足!");
                    return;
                }
            }
            //6.进行下单操作
            String orderNo = orderService.getOrderNo();
            log.info("当前请求允许下单,requestId:{},orderNo:{}", req.getRequestId(), req.getOrderNo());
            req.setOrderNo(orderNo);
            req.setPayAmount(payAmount);
            amqpTemplate.convertAndSend(QueuesType.ORDER_SAVE_SYNC, JSON.toJSONString(req));


        } catch (Exception e) {
            log.error(e.getMessage(), e);
            if (req != null) {
                cacheService.setRequestIdStatus(req.getRequestId(), "ERROR:系统异常");
            }
        } finally {
            try {
                channel.basicAck(m.getMessageProperties().getDeliveryTag(), false);
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        }
    }

    /***
     * 订单入库处理，
     * 设置了确认模式，只有消费成功，消息才会被从MQ中删除
     * 设置了同时只有5个消费端，每次只获取5条消息
     * @param object
     */
    @RabbitHandler
    @RabbitListener(queues = QueuesType.ORDER_SAVE_SYNC, containerFactory = "saveOrderTaskContainerFactory")
    public void orderSave(Object object) {
        try {
            Message m = (Message) object;
            String message = new String(m.getBody(), "UTF-8");
            if (StringUtils.isEmpty(message)) {
                log.info("消息内容为空，不处理！");
                return;
            }
            log.info("保存订单处理接收到消息:{}", message);
            OrderReq req = JSON.parseObject(message, OrderReq.class);

            ActivityEntity act = null;
            if (req.getActId() != null) {
                act = activityService.findById(req.getActId());
            } else {
                act = activityService.findBySn(req.getSn());
            }
            String json = goodsInfoService.findById(req.getGoodsInfoId());
            GoodsInfoEntity goods = JSON.parseObject(json, GoodsInfoEntity.class);
            OrderEntity order = orderProcesser.saveOrder(req, act, goods);
            cacheService.setRequestIdStatus(req.getRequestId(), "SUCCESS:" + order.getOrderNo());
            //保存订单数据到缓存当中
            cacheService.putOrder(act, order);
            String actCountCacheKey = act.getSn() + ":" + act.getId();
            cacheService.incrActOrderSuccess(actCountCacheKey);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

}
